home *** CD-ROM | disk | FTP | other *** search
- ;****************************************************************************
- ; XMS2EMS is an EMS 3.2 expanded memory manager (EMM) that uses extended
- ; memory managed by HIMEM.SYS to store data written to expanded memory.
- ; Its syntax is:
- ;
- ; DEVICE=XMS2EMS.SYS [memory] [/H=nnn]
- ;
- ; where "memory" is amount of expanded memory to be created (in kilobytes)
- ; and "nnn" is the number of handles desired (range=8 to 255, default=64).
- ; If the amount of expanded memory to be made available to the system is not
- ; specified, XMS2EMS defaults to 256K. The maximum that XMS2EMS supports is
- ; 8192 (8MB), the minimum 256K.
- ;
- ; DEVELOPER'S NOTES:
- ; ******************
- ;
- ; To manage EMS memory, XMS2EMS maintains a table called PAGE_TABLE that
- ; contains one entry for each 16K EMS page. Each entry is structured as
- ; follows:
- ;
- ; HANDLE DW ?
- ; LOGICAL_PAGE DW ?
- ;
- ; HANDLE is the number of the handle that owns the page. A value of FFFFh
- ; indicates the page is free. LOGICAL_PAGE is the logical page number for
- ; the range of memory assigned to the handle. It is only meaningful if
- ; the HANDLE field contains a valid (non-FFFFh) value.
- ;
- ; XMS2EMS also contains one table that holds information about handles.
- ; HNDL_TABLE contains one 1-byte entry for each handle supported. If the
- ; byte that corresponds to a handle is 0, then the handle is unassigned.
- ; This isn't strictly required in EMS 3.2, but it is required for 4.0.
- ;
- ; XMS2EMS implements a number of procedures that functions may call upon
- ; to perform certain often-needed tasks such as verifying that a handle is
- ; valid or mapping a logical page to a physical page. The procedures are:
- ;
- ; GET_FREE_PAGES Return the number of unallocated EMS pages
- ; GET_FREE_HANDLE Return the number of the next free handle
- ; ALLOCATE_PAGES Allocate EMS memory and validate the handle
- ; RELEASE_PAGES Release all EMS pages and invalidate the handle
- ; CHECK_HANDLE Verify that the handle is valid
- ; CHECK_SAVE_MAP Search the save area for a specified entry
- ; GET_PAGE_COUNT Return the number of EMS pages assigned to a handle
- ; GET_ABS_PAGE Convert logical page number to absolute page number
- ; MAP_EMS_PAGE Map a logical (absolute) page to a physical page
- ; RESTORE_PAGE_MAP Restore a mapping context
- ;
- ; Calling conventions are documented in the procedure headers.
- ;****************************************************************************
-
- KEEPBX equ 4
- KEEPCX equ 2
- KEEPDX equ 1
- KEEPNONE equ 0
-
- HARDWARE_ERROR equ 81h ;EMS error returns
- INVALID_HANDLE equ 83h
- INVALID_FUNCTION equ 84h
- NO_MORE_HANDLES equ 85h
- TOO_FEW_TOTAL_PAGES equ 87h
- TOO_FEW_LOGICAL_PAGES equ 88h
- ZERO_PAGES_REQUESTED equ 89h
- INVALID_LOGICAL_PAGE equ 8Ah
- INVALID_PHYS_PAGE equ 8Bh
- SAVE_AREA_FULL equ 8Ch
- MAP_ALREADY_SAVED equ 8Dh
- MAP_NOT_FOUND equ 8Eh
- INVALID_SUBFUNCTION equ 8Fh
-
- code segment
- assume cs:code,ds:nothing
- org 00h
-
- ;////////////////////////////////////////////////////////////////////////////
- ; Device Driver Header
- ;////////////////////////////////////////////////////////////////////////////
-
- header dd 0FFFFh ;Pointer to next device
- dw 8000h ;Device attribute word
- dw offset strat ;Strategy routine address
- dw offset intr ;Interrupt routine address
- devname db "EMMXXXX0" ;Device name
-
- ;////////////////////////////////////////////////////////////////////////////
- ; Strategy Routine
- ;////////////////////////////////////////////////////////////////////////////
-
- rqst_header dd ? ;Request header
-
- strat proc far
- mov word ptr cs:[rqst_header],bx
- mov word ptr cs:[rqst_header+2],es
- ret
- strat endp
-
- ;////////////////////////////////////////////////////////////////////////////
- ; Interrupt Routine
- ;////////////////////////////////////////////////////////////////////////////
-
- intr proc far
- push ax ;Save registers
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
-
- les di,cs:[rqst_header] ;Point ES:DI to request
- cmp byte ptr es:[di+2],0 ;header and exit if command
- jne intr_exit ;code is not 0
-
- call init ;Initialize the driver
-
- intr_exit: mov word ptr es:[di+3],100h ;"Done" code
- pop es ;Restore registers and
- pop ds ;return to caller
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- intr endp
-
- ;****************************************************************************
- ; Device Driver Data
- ;****************************************************************************
-
- ftable dw offset emm_function_01 ;Jump table
- dw offset emm_function_02
- dw offset emm_function_03
- dw offset emm_function_04
- dw offset emm_function_05
- dw offset emm_function_06
- dw offset emm_function_07
- dw offset emm_function_08
- dw offset emm_function_09
- dw offset emm_function_10
- dw offset emm_function_11
- dw offset emm_function_12
- dw offset emm_function_13
- dw offset emm_function_14
- dw offset emm_function_15
-
- xmm dd ? ;XMS driver entry point
- handles dw 64 ;Number of EMM handles
- memory dw 256 ;Kilobytes available
- pages dw ? ;EMS pages available
- page_frame dw ? ;Page frame segment
- emb_handle dw ? ;EMB handle
- active_handles db 1 ;Active EMS handles
- hndl_table_addr dw ? ;Address of handle table
- entry_flag db 0 ;0=First call to INT 67h
- ems_version db 32h ;EMS version number
-
- page_map_0 dw 0FFFFh ;Array that holds the
- page_map_1 dw 0FFFFh ;absolute page numbers
- page_map_2 dw 0FFFFh ;mapped to physical
- page_map_3 dw 0FFFFh ;pages 0 thru 3
-
- saved_maps db 240h dup (0FFh) ;Page map save area
-
- ;****************************************************************************
- ; INT67H handles calls to the expanded memory manager. The value passed
- ; back to this routine in BP by the function routines determines what reg-
- ; isters are popped off the stack. Bit 0 corresponds to DX; bit 1 to CX;
- ; and bit 2 to BX. If the bit is set, then the corresponding register is
- ; not restored from the stack.
- ;****************************************************************************
-
- assume ds:nothing
-
- int67h proc far
- sti ;Enable interrupts
- cmp ah,40h ;Return error code 84h if
- jb invalid_code ;function code is less
- cmp ah,4Eh ;than 40h or greater
- ja invalid_code ;than 4Eh
-
- push bp ;Save registers
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
-
- cld ;Clear direction flag
- push bx ;Save BX
- mov bx,cs ;Point DS to this segment
- mov ds,bx
- assume ds:code
- mov es,bx ;Point ES to this segment
-
- cmp entry_flag,0 ;Initialize the driver's
- jne int67h_1 ;data area if this is
- mov entry_flag,1 ;the first time INT 67h
- call init_ems_data ;has been called
-
- int67h_1: sub ah,40h ;Convert function number in
- mov bl,ah ;AX to offset address of
- xor bh,bh ;handling routine
- shl bx,1
- mov ax,[offset ftable+bx]
- pop bx ;Restore BX
-
- call ax ;Call EMM function
-
- pop es ;Restore registers and exit
- pop ds
- assume ds:nothing
- pop di
- pop si
-
- shr bp,1 ;Restore DX if bit in BP
- jc popreg1 ;is not set
- pop dx
- jmp short popreg2
- popreg1: add sp,2
-
- popreg2: shr bp,1 ;Restore CX if bit in BP
- jc popreg3 ;is not set
- pop cx
- jmp short popreg4
- popreg3: add sp,2
-
- popreg4: shr bp,1 ;Restore BX if bit in BP
- jc popreg5 ;is not set
- pop bx
- jmp short popreg6
- popreg5: add sp,2
-
- popreg6: add sp,2 ;Skip AX
- pop bp ;Restore BP
- iret ;Return to caller
-
- invalid_code: mov ah,INVALID_FUNCTION ;Function not supported
- iret
- int67h endp
-
- ;****************************************************************************
- ; INIT_EMS_DATA initializes the driver's data space.
- ;****************************************************************************
-
- assume ds:code
-
- init_ems_data proc near
- push ax ;Save registers
- push bx
- push cx
- push di
- push es
-
- mov di,offset page_table ;Initialize the page table
- mov cx,pages ;by filling it with FFs
- shl cx,1
- mov ax,0FFFFh
- rep stosw
-
- mov di,hndl_table_addr ;Initialize the handle table
- mov cx,handles ;by filling it with
- xor al,al ;zeroes
- rep stosb
- mov di,hndl_table_addr ;Mark handle 0 as in use
- mov byte ptr [di],1
-
- pop es ;Restore registers and
- pop di ;exit
- pop cx
- pop bx
- pop ax
- ret
- init_ems_data endp
-
- ;****************************************************************************
- ; EMM Function 1 (Get Status)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_01 proc near
- xor ah,ah ;Zero AH for return
- mov bp,KEEPNONE
- ret
- emm_function_01 endp
-
- ;****************************************************************************
- ; EMM Function 2 (Get Page Frame Segment Address)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_02 proc near
- mov bx,page_frame ;Place page frame address
- xor ah,ah ;in BX and zero AH
- mov bp,KEEPBX
- ret
- emm_function_02 endp
-
- ;****************************************************************************
- ; EMM Function 3 (Get Unallocated Page Count)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_03 proc near
- call get_free_pages ;Free pages in BX
- mov dx,pages ;Total pages in DX
- xor ah,ah ;Zero AH for return
- mov bp,KEEPBX or KEEPDX
- ret
- emm_function_03 endp
-
- ;****************************************************************************
- ; EMM Function 4 (Allocate Pages)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_04 proc near
- mov ah,ZERO_PAGES_REQUESTED ;Error if zero pages were
- cmp bx,0 ;requested
- je emm4_exit
-
- mov ah,TOO_FEW_TOTAL_PAGES ;Error if request exceeds
- cmp bx,pages ;count of total pages
- ja emm4_exit
-
- mov dx,bx ;Transfer count
- call get_free_pages ;Error if request
- mov ah,TOO_FEW_LOGICAL_PAGES ;exceeds count of
- cmp dx,bx ;pages free
- ja emm4_exit
-
- push dx ;Save page count
- call get_free_handle ;Get first free handle
- pop cx ;Retrieve page count
- mov ah,NO_MORE_HANDLES ;Error if no handles are
- jc emm4_exit ;currently available
-
- call allocate_pages ;Allocate the EMS pages
- xor ah,ah ;Zero AH for return
- emm4_exit: mov bp,KEEPDX
- ret
- emm_function_04 endp
-
- ;****************************************************************************
- ; EMM Function 5 (Map/Unmap Handle Page)
- ;
- ; Note: Logic was added in version 1.1 so that a logical page number
- ; equal to FFFFh unmaps the corresponding physical page.
- ;****************************************************************************
-
- assume ds:code
-
- PHYSICAL_PAGE equ byte ptr [bp+18]
- LOGICAL_PAGE equ word ptr [bp]
-
- emm_function_05 proc near
- push bx ;Save logical page number
- mov bp,sp ;Make values addressable
-
- call check_handle ;Error if handle is not
- mov ah,INVALID_HANDLE ;valid
- jc emm5_exit
-
- mov ah,INVALID_PHYS_PAGE ;Error if physical page
- cmp PHYSICAL_PAGE,3 ;number is greater
- ja emm5_exit ;than 3
-
- mov bx,0FFFFh ;Set absolute page to FFFFh
- cmp LOGICAL_PAGE,0FFFFh ;Branch if the logical page
- je emm05_1 ;number is FFFFh
-
- call get_page_count ;Get handle's page count
- mov ah,INVALID_LOGICAL_PAGE ;Error if logical page
- cmp LOGICAL_PAGE,bx ;number is out of
- jae emm5_exit ;range
-
- mov bx,LOGICAL_PAGE ;Compute the absolute page
- call get_abs_page ;number
- mov bx,ax ;Transfer result to BX
- emm05_1: mov al,PHYSICAL_PAGE ;Physical page number in AL
- call map_ems_page ;Map the page
- mov ah,HARDWARE_ERROR ;Exit on error
- jc emm5_exit
- xor ah,ah ;Zero AH for return
-
- emm5_exit: mov bp,KEEPNONE ;Set BP
- add sp,2 ;Clear the stack
- ret
- emm_function_05 endp
-
- ;****************************************************************************
- ; EMM Function 6 (Deallocate Pages)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_06 proc near
- call check_handle ;Error if DX contains an
- mov ah,INVALID_HANDLE ;invalid handle
- jc emm6_exit
- call release_pages ;Deallocate the pages
- xor ah,ah ;Zero AH for return
- emm6_exit: mov bp,KEEPNONE
- ret
- emm_function_06 endp
-
- ;****************************************************************************
- ; EMM Function 7 (Get Version)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_07 proc near
- mov al,ems_version ;Load version number in AL
- xor ah,ah ;Zero AH for return
- mov bp,KEEPNONE
- ret
- emm_function_07 endp
-
- ;****************************************************************************
- ; EMM Function 8 (Save Page Map)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_08 proc near
- call check_handle ;Error if DX contains an
- mov ah,INVALID_HANDLE ;invalid handle
- jc emm8_exit
-
- call check_save_map ;Error if save area already
- mov ah,MAP_ALREADY_SAVED ;contains a map for this
- jnc emm8_exit ;handle
-
- push dx ;Save handle
- mov dx,0FFh ;Find address of first free
- call check_save_map ;map in the save area
- pop dx ;Retrieve handle
- mov ah,SAVE_AREA_FULL ;Error if the save area
- jc emm8_exit ;is full
-
- mov di,si ;Store the handle number
- mov [di],dl
- inc di
- mov si,offset page_map_0 ;Copy maps for pages 0
- mov cx,4 ;thru 3 to the save
- rep movsw ;area
- xor ah,ah ;Zero AH for return
- emm8_exit: mov bp,KEEPNONE
- ret
- emm_function_08 endp
-
- ;****************************************************************************
- ; EMM Function 9 (Restore Page Map)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_09 proc near
- call check_handle ;Error if DX contains an
- mov ah,INVALID_HANDLE ;invalid handle
- jc emm9_exit
-
- call check_save_map ;Error if no map exists
- mov ah,MAP_NOT_FOUND ;for this handle
- jc emm9_exit
-
- mov byte ptr [si],0FFh ;Mark map as unused
- inc si ;Advance SI to saved map
- call restore_page_map ;Restore the page map
- mov ah,HARDWARE_ERROR ;Exit on error
- jc emm9_exit
- xor ah,ah ;Zero AH for return
- emm9_exit: mov bp,KEEPNONE
- ret
- emm_function_09 endp
-
- ;****************************************************************************
- ; EMM Function 10 (Reserved)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_10 proc near
- mov ah,INVALID_FUNCTION
- mov bp,KEEPNONE
- ret
- emm_function_10 endp
-
- ;****************************************************************************
- ; EMM Function 11 (Reserved)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_11 proc near
- mov ah,INVALID_FUNCTION
- mov bp,KEEPNONE
- ret
- emm_function_11 endp
-
- ;****************************************************************************
- ; EMM Function 12 (Get Handle Count)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_12 proc near
- mov bl,active_handles ;Place count in BL
- xor bh,bh ;Byte to word in BX
- xor ah,ah ;Zero AH for return
- emm12_exit: mov bp,KEEPBX
- ret
- emm_function_12 endp
-
- ;****************************************************************************
- ; EMM Function 13 (Get Handle Pages)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_13 proc near
- xor bx,bx ;Exit with count equal to
- or dx,dx ;0 if handle number is 0
- jz emm13_1
- call check_handle ;Error if DX contains an
- mov ah,INVALID_HANDLE ;invalid handle
- jc emm13_exit
- call get_page_count ;Get page count in BX
- emm13_1: xor ah,ah ;Zero AH for return
- emm13_exit: mov bp,KEEPBX
- ret
- emm_function_13 endp
-
- ;****************************************************************************
- ; EMM Function 14 (Get All Handle Pages)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_14 proc near
- mov bp,sp ;Restore value of ES on
- mov es,[bp+2] ;entry to this function
- mov ax,cs ;Point ES back to this
- mov es,ax ;segment
- mov dx,-1 ;Initialize handle number
- mov cl,active_handles ;Initialize handle count
- xor ch,ch ;Byte to word in CX
-
- emm14_1: inc dx ;Increment handle
- push cx ;Save count
- push di ;Save DI
- call check_handle ;See if handle in DX is valid
- pop di ;Retrieve DI
- pop cx ;Retrieve count
- jc emm14_1 ;Branch if handle invalid
-
- push cx ;Save count again
- call get_page_count ;Get page count if valid
- mov es,[bp+2] ;Point ES to user data space
- mov es:[di],dx ;Store handle number
- mov es:[di+2],bx ;Store page count
- add di,4 ;Advance DI
- mov ax,cs ;Point ES back to this
- mov es,ax ;segment
- pop cx ;Retrieve count
- loop emm14_1 ;Loop until done
-
- emm14_exit: jmp emm_function_12 ;Exit through function 12
- emm_function_14 endp
-
- ;****************************************************************************
- ; EMM Function 15 (Get/Set Page Map)
- ;****************************************************************************
-
- assume ds:code
-
- emm_function_15 proc near
- mov bp,sp ;Make stack addressable
- mov al,byte ptr [bp+16] ;Retrieve subfunction code
- mov ah,INVALID_SUBFUNCTION ;Branch if subfunction code
- cmp al,0 ;is other than 0
- jne emm15_1
- mov bp,sp ;Restore value of ES on
- mov es,[bp+2] ;entry to this function
- mov si,offset page_map_0 ;Copy maps for pages 0
- mov cx,4 ;thru 3 to the user's
- rep movsw ;data space
- xor ah,ah ;Zero AH for return
- jmp short emm15_exit ;Exit
- ;
- ; Function 15, Subfunction 1.
- ;
- emm15_1: cmp al,1 ;Branch if subfunction code
- jne emm15_2 ;is other than 1
- mov bp,sp ;Restore value of DS on
- emm15_1_1: mov ds,[bp+4] ;entry to this function
- assume ds:nothing
- call restore_page_map ;Restore the page map
- mov ah,HARDWARE_ERROR ;Exit on error
- jc emm15_exit
- xor ah,ah ;Zero AH for return
- jmp short emm15_exit ;Exit
- assume ds:code
- ;
- ; Function 15, Subfunction 2.
- ;
- emm15_2: cmp al,2 ;Branch if subfunction code
- jne emm15_3 ;is other than 2
- mov bp,sp ;Restore value of ES on
- mov es,[bp+2] ;entry to this function
- push si ;Save SI
- mov si,offset page_map_0 ;Copy maps for pages 0
- mov cx,4 ;thru 3 to the user's
- rep movsw ;data space
- pop si ;Restore SI
- jmp emm15_1_1 ;Branch and finish
- ;
- ; Function 15, Subfunction 3.
- ;
- emm15_3: cmp al,3 ;Error if subfunction number
- jne emm15_exit ;is other than 3
- mov ax,0008h ;Prepare AX for return
- emm15_exit: mov bp,KEEPNONE
- ret
- emm_function_15 endp
-
- ;****************************************************************************
- ; GET_FREE_PAGES returns the number of unallocated pages in BX. On entry,
- ; DS must point to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- get_free_pages proc near
- mov si,offset page_table ;Point SI to page table
- mov cx,pages ;Set CX to number of pages
- xor bx,bx ;Zero unallocated page count
- getfree1: lodsw ;Get page table entry
- cmp ax,0FFFFh ;Branch if allocated
- jne getfree2
- inc bx ;Increment count
- getfree2: add si,2 ;Skip next field in table
- loop getfree1 ;Loop until done
- ret
- get_free_pages endp
-
- ;****************************************************************************
- ; GET_FREE_HANDLE returns the number of the lowest available handle in DX.
- ; On return, carry set means no handles are available. On entry, ES must
- ; point to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- get_free_handle proc near
- mov cx,handles ;Place count in CX
- mov al,00h ;Search the handle table
- mov di,hndl_table_addr ;until an unallocated
- repne scasb ;handle is found
- je gethand1 ;Branch if handle found
- stc ;Set carry and return
- ret
- gethand1: inc cx ;Compute handle number
- mov dx,handles ;in DX
- sub dx,cx
- clc ;Clear carry and return
- ret
- get_free_handle endp
-
- ;****************************************************************************
- ; ALLOCATE_PAGES allocates the number of EMS pages in CX to the handle in
- ; DX and validates the handle. No checking is performed to make sure the
- ; number of pages requested in CX are available. On entry, DS must point
- ; to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- allocate_pages proc near
- inc active_handles ;Increment handle count
- mov si,hndl_table_addr ;Validate the handle
- add si,dx
- mov byte ptr [si],1
- jcxz allocpage2 ;Branch if CX=0
- mov bx,0 ;Initialize log page number
- mov si,offset page_table ;Point SI to page table
- allocpage1: lodsw ;Get an entry
- add si,2 ;Skip logical page number
- cmp ax,0FFFFh ;Branch if the page is
- jne allocpage1 ;already allocated
- mov [si-4],dx ;Write handle to table
- mov [si-2],bx ;Write logical page number
- inc bx ;Increment page number
- loop allocpage1 ;Loop until done
- allocpage2: ret
- allocate_pages endp
-
- ;****************************************************************************
- ; RELEASE_PAGES deallocates all pages that belong to the handle in DX and
- ; invalidates the handle. On entry, both DS and ES must point to the code
- ; segment.
- ;****************************************************************************
-
- assume ds:code
-
- release_pages proc near
- cmp dx,0 ;Branch if handle number
- je relpage0 ;is 0
-
- dec active_handles ;Decrement handle count
- mov si,hndl_table_addr ;Invalidate the handle
- add si,dx
- mov byte ptr [si],0
-
- relpage0: mov si,offset page_table ;Point SI to page table
- mov cx,pages ;Initialize page count
- relpage1: lodsw ;Get a page table entry
- cmp ax,dx ;Branch if the page belongs
- jne relpage2 ;to another handle
- mov word ptr [si-2],0FFFFh ;Mark the page as unused
- mov word ptr [si],0000h ;Zero the logical page number
- relpage2: add si,2 ;Skip logical page number
- loop relpage1 ;Loop until done
- ret
- release_pages endp
-
- ;****************************************************************************
- ; CHECK_HANDLE returns with carry clear if the handle in DX is a valid
- ; handle, carry set if DX does not contain a valid handle. On entry, DS
- ; must point to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- check_handle proc near
- cmp dx,handles ;Handle invalid if number is
- jae handle_bad ;greater than handle count
- mov si,hndl_table_addr ;Handle invalid if corre-
- add si,dx ;sponding byte in handle
- cmp byte ptr [si],0 ;table is 0
- je handle_bad
- clc ;Clear carry and return
- ret
- handle_bad: stc ;Set carry and return
- ret
- check_handle endp
-
- ;****************************************************************************
- ; CHECK_SAVE_MAP returns with carry clear if the page map save area
- ; contains a page map for the handle in DX, carry set if it does not.
- ; If a handle is found, the offset address of the corresponding page
- ; map is returned in SI. To search for a free map in the save area,
- ; call this procedure with DX set to 0FFh. On entry, DS must point
- ; to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- check_save_map proc near
- mov si,offset saved_maps ;Point SI to save area
- mov cx,64 ;Initialize count in CX
- csm1: cmp byte ptr [si],dl ;Check one entry
- je map_found ;Branch if handle matches
- add si,9 ;Point SI to next entry
- loop csm1 ;Loop until done
- stc ;Set carry and return
- ret
- map_found: clc ;Clear carry and return
- ret
- check_save_map endp
-
- ;****************************************************************************
- ; GET_PAGE_COUNT returns in BX the number of logical pages allocated to
- ; the handle in DX. No checking is performed to make sure the handle is
- ; valid. On entry, DS must point to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- get_page_count proc near
- mov si,offset page_table ;Point SI to page table
- mov cx,pages ;Initialize count in CX
- xor bx,bx ;Initalize page count
- gpc1: lodsw ;Get a page table entry
- cmp ax,dx ;Increment page count if
- jne gpc2 ;the handles match
- inc bx
- gpc2: add si,2 ;Skip logical page number
- loop gpc1 ;Loop until done
- ret
- get_page_count endp
-
- ;****************************************************************************
- ; GET_ABS_PAGE returns in AX the absolute page number that corresponds to
- ; the handle in DX and the logical page number in BX. No checking is per-
- ; formed to make sure the handle and the logical page number are valid.
- ; On entry, DS must point to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- get_abs_page proc near
- mov si,offset page_table ;Point SI to page table
- mov cx,pages ;Initialize page count
- gpa1: lodsw ;Get a page table entry
- cmp ax,dx ;Branch if page does not
- jne gpa2 ;belong to handle in DX
- cmp bx,[si] ;Branch if logical page
- je gpa3 ;numbers match
- gpa2: add si,2 ;Skip logical page number
- loop gpa1 ;Loop back for more
- gpa3: mov ax,pages ;Compute absolute page
- sub ax,cx ;number in AX
- ret
- get_abs_page endp
-
- ;****************************************************************************
- ; MAP_EMS_PAGE maps the absolute page whose number is passed in BX
- ; to the physical page whose number is passed in AL. On return, carry
- ; clear means the page was mapped. Carry set means an error occurred.
- ; On entry, DS must point to the code segment.
- ;****************************************************************************
-
- EMS_PPAGE equ byte ptr [bp+2]
- EMS_APAGE equ word ptr [bp]
-
- assume ds:code
-
- map_ems_page proc near
- push bp ;Save BP
- push ax ;Save page numbers on the
- push bx ;stack
- mov bp,sp ;Make stack addressable
-
- mov si,offset page_map_0 ;Compute offset into page
- xor ah,ah ;map array for specified
- shl ax,1 ;physical page
- add si,ax
- mov ax,[si] ;Get absolute page number
- cmp ax,0FFFFh ;Branch if the page is
- je mep1 ;currently unmapped
-
- mov bl,EMS_PPAGE ;Get physical page number
- call copy_p2a ;Copy page to XMS memory
- jc mep_error ;Exit on error
-
- mep1: mov ax,EMS_APAGE ;Get absolute page number
- cmp ax,0FFFFh ;Branch if page number is
- je mep2 ;FFFFh
- mov bl,EMS_PPAGE ;Get physical page number
- call copy_a2p ;Copy page from XMS memory
- jc mep_error ;Exit on error
-
- mep2: mov si,offset page_map_0 ;Compute offset into page
- mov al,EMS_PPAGE ;map array for specified
- xor ah,ah ;physical page
- shl ax,1
- add si,ax
- mov bx,EMS_APAGE ;Get absolute page number
- mov word ptr [si],bx ;Store absolute page number
-
- add sp,4 ;Clear the stack
- pop bp ;Restore BP
- clc ;Clear carry
- ret ;Return
-
- mep_error: add sp,4 ;Clear the stack
- pop bp ;Restore BP
- stc ;Set carry
- ret ;Return
- map_ems_page endp
-
- ;****************************************************************************
- ; COPY_P2A copies the physical page whose page number is passed in BL to the
- ; page in XMS memory whose absolute page number is passed in AX. On return,
- ; carry set means the operation succeeded, carry set means it did not. On
- ; entry, DS must point to the code segment.
- ;****************************************************************************
-
- XMS_LENGTH_LO equ word ptr [bp]
- XMS_LENGTH_HI equ word ptr [bp+2]
- XMS_SRC_HANDLE equ word ptr [bp+4]
- XMS_SRC_OFFSET_LO equ word ptr [bp+6]
- XMS_SRC_OFFSET_HI equ word ptr [bp+8]
- XMS_DST_HANDLE equ word ptr [bp+10]
- XMS_DST_OFFSET_LO equ word ptr [bp+12]
- XMS_DST_OFFSET_HI equ word ptr [bp+14]
-
- assume ds:code
-
- copy_p2a proc near
- push bp ;Save BP
- sub sp,16 ;Make room on stack
- mov bp,sp ;Make stack addressable
-
- mov XMS_LENGTH_LO,16384 ;Set block length (16K)
- mov XMS_LENGTH_HI,0
-
- mov dx,emb_handle ;Set destination handle
- mov XMS_DST_HANDLE,dx
-
- xor dx,dx ;Compute offset into EMB
- mov cx,14 ;that corresponds to the
- cp2a_1: shl ax,1 ;absolute page number in
- rcl dx,1 ;AX
- loop cp2a_1
- mov XMS_DST_OFFSET_LO,ax ;Write result to XMS
- mov XMS_DST_OFFSET_HI,dx ;parameter block
-
- mov XMS_SRC_HANDLE,0 ;Set source handle
-
- mov ax,16384 ;Compute offset into page
- xor bh,bh ;frame that corresponds to
- mul bx ;the physical page number
- mov XMS_SRC_OFFSET_LO,ax ;Write result to XMS
- mov ax,page_frame ;parameter block
- mov XMS_SRC_OFFSET_HI,ax
-
- push ds ;Save DS
- mov si,bp ;Point DS:SI to XMS
- mov ax,ss ;parameter block
- mov ds,ax
- assume ds:nothing
- mov ah,0Bh ;XMS function code in AH
- call cs:[xmm] ;Execute block move
- pop ds ;Retrieve DS
- assume ds:code
- or ax,ax ;Branch on error
- jz cp2a_error
-
- add sp,16 ;Clear the stack
- pop bp ;Restore BP
- clc ;Clear carry
- ret ;Return
-
- cp2a_error: add sp,16 ;Clear the stack
- pop bp ;Restore BP
- stc ;Set carry
- ret ;Return
- copy_p2a endp
-
- ;****************************************************************************
- ; COPY_A2P copies the page in XMS memory whose page number is passed in
- ; AX to the physical page whose page number is passed in BL. On return,
- ; carry set means the operation succeeded, carry set means it did not.
- ; On entry, DS must point to the code segment.
- ;****************************************************************************
-
- assume ds:code
-
- copy_a2p proc near
- push bp ;Save BP
- sub sp,16 ;Make room on stack
- mov bp,sp ;Make stack addressable
-
- mov XMS_LENGTH_LO,16384 ;Set block length (16K)
- mov XMS_LENGTH_HI,0
-
- mov dx,emb_handle ;Set source handle
- mov XMS_SRC_HANDLE,dx
-
- xor dx,dx ;Compute offset into EMB
- mov cx,14 ;that corresponds to the
- ca2p_1: shl ax,1 ;absolute page number in
- rcl dx,1 ;AX
- loop ca2p_1
- mov XMS_SRC_OFFSET_LO,ax ;Write result to XMS
- mov XMS_SRC_OFFSET_HI,dx ;parameter block
-
- mov XMS_DST_HANDLE,0 ;Set destination handle
-
- mov ax,16384 ;Compute offset into page
- xor bh,bh ;frame that corresponds to
- mul bx ;the physical page number
- mov XMS_DST_OFFSET_LO,ax ;Write result to XMS
- mov ax,page_frame ;parameter block
- mov XMS_DST_OFFSET_HI,ax
-
- push ds ;Save DS
- mov si,bp ;Point DS:SI to XMS
- mov ax,ss ;parameter block
- mov ds,ax
- assume ds:nothing
- mov ah,0Bh ;XMS function code in AH
- call cs:[xmm] ;Execute block move
- pop ds ;Retrieve DS
- assume ds:code
- or ax,ax ;Branch on error
- jz ca2p_error
-
- add sp,16 ;Clear the stack
- pop bp ;Restore BP
- clc ;Clear carry
- ret ;Return
-
- ca2p_error: add sp,16 ;Clear the stack
- pop bp ;Restore BP
- stc ;Set carry
- ret ;Return
- copy_a2p endp
-
- ;****************************************************************************
- ; RESTORE_PAGE_MAP restores the page map whose address is passed in DS:SI.
- ; On return, carry clear means the mapping succeeded. Carry set means an
- ; error occurred.
- ;****************************************************************************
-
- assume ds:nothing
-
- restore_page_map proc near
- mov cx,4 ;Initialize page count
- rpm_loop: lodsw ;Get absolute page number
- push cx ;Save registers
- push si
- push ds
- mov bx,cs ;Point DS back to this
- mov ds,bx ;segment for now
- mov bx,ax ;Transfer it to BX
- mov ax,4 ;Compute physical page
- sub ax,cx ;number in AX
- call map_ems_page ;Map the EMS page
- pop ds ;Restore registers
- pop si
- pop cx
- jc rpm_exit ;Exit on error
- loop rpm_loop ;Loop until done
- clc ;Clear carry for exit
- rpm_exit: ret
- restore_page_map endp
-
- ;****************************************************************************
- ; INIT parses the DEVICE= line and initializes the device driver.
- ;****************************************************************************
-
- page_table label byte
-
- copyright db "XMS2EMS 1.1 Copyright (c) 1993 Jeff Prosise",13,10
- db "From: PC Magazine DOS 6 Memory Management with "
- db "Utilities",13,10,"$"
-
- errmsg0 db "ERROR: $"
- errmsg1 db "An expanded memory manager is already installed"
- db 13,10,"$"
- errmsg2 db "HIMEM.SYS must be installed before XMS2EMS.SYS"
- db 13,10,"$"
- errmsg3 db "Invalid parameter or parameter out of range"
- db 13,10,"$"
- errmsg4 db "XMS2EMS not installed"
- db 13,10,"$"
- errmsg5 db "Insufficient XMS memory available",13,10,"$"
-
- msg1 db "Expanded memory available: $"
- msg2 db "K",13,10,"$"
-
- assume cs:code,ds:nothing
-
- init proc near
- mov ax,cs ;Point DS to code segment
- mov ds,ax
- mov ah,09h ;Display installation
- mov dx,offset copyright ;message
- int 21h
-
- push di ;Make sure there's not
- push es ;an EMM already loaded
- xor ax,ax
- mov ds,ax
- mov es,ds:[19Eh]
- mov ax,cs
- mov ds,ax
- assume ds:code
- mov si,offset devname
- mov di,10
- mov cx,8
- repe cmpsb
- pop es
- pop di
- jne init2
- ;
- ; Display error message, zero the break address, and return.
- ;
- mov dx,offset errmsg1
- init_error: mov ax,cs ;Point DS to code segment
- mov ds,ax
- push dx ;Save message pointer
- mov ah,09h ;Print "ERROR:"
- mov dx,offset errmsg0
- int 21h
- pop dx ;Retrieve message pointer
- mov ah,09h ;Print error message
- int 21h
- mov ah,09h ;Print "XMS2EMS not
- mov dx,offset errmsg4 ;installed"
- int 21h
- mov word ptr es:[di+14],0 ;Zero the break address
- mov word ptr es:[di+16],cs
- ret
- ;
- ; Make sure HIMEM.SYS is loaded and get the driver's entry point.
- ;
- init2: mov ax,4300h ;Make sure the driver is
- int 2Fh ;present with function
- mov dx,offset errmsg2 ;4300h
- cmp al,80h
- jne init_error
-
- push es ;Get its entry point address
- mov ax,4310h ;with function 4310h
- int 2Fh
- mov word ptr xmm,bx
- mov word ptr xmm[2],es
- pop es
- ;
- ; Parse the DEVICE= line for parameters.
- ;
- lds si,es:[di+18] ;Point DS:SI to the DEVICE=
- assume ds:nothing ;line
- cld ;Clear direction flag
-
- call finddelim ;Skip device driver name
- jc init5 ;Branch if end of line
-
- init3: call findchar ;Find the first character
- jc init5 ;Branch if end of line
-
- cmp byte ptr [si],"/" ;Branch if the character is
- jne init4 ;not a "/"
- inc si ;Advance past the "/"
- lodsw ;Get the next two characters
- and al,0DFh ;Capitalize the first one
- mov dx,offset errmsg3 ;Initialize error pointer
- cmp ax,3D48h ;Error if not "H="
- jne init_error
- call asc2bin ;Get the number following
- mov dx,offset errmsg3 ;the equal sign
- jc init_error
- cmp ax,8 ;Check the range
- jb init_error
- cmp ax,255
- ja init_error
- mov cs:[handles],ax ;Store number of handles
- jmp init3 ;Return to parsing loop
-
- init4: call asc2bin ;Get the number of kilobytes
- mov dx,offset errmsg3 ;requested
- jc init_error2
- cmp ax,256 ;Check the range
- jb init_error2
- cmp ax,8192
- ja init_error2
- mov cs:[memory],ax ;Store kilobytes requested
- jmp init3 ;Return to parsing loop
- ;
- ; Allocate an extended memory block (EMB) from the XMS driver.
- ;
- init5: mov ax,cs ;Point DS back to the
- mov ds,ax ;code segment
- assume ds:code
-
- add memory,15 ;Round MEMORY value up to
- and memory,0FFF0h ;the nearest 16K boundary
-
- get_emb: mov ah,09h ;Request an EMB of the
- mov dx,memory ;same length
- call xmm
- or ax,ax ;Branch if no error
- jnz init7
-
- check_emb: mov ah,08h ;Get the size of the largest
- call xmm ;free EMB
- mov dx,offset errmsg5 ;Error if it's smaller than
- cmp ax,256 ;256K
- jae init6
-
- init_error2: jmp init_error
-
- init6: and ax,0FFF0h ;Round down to the nearest
- mov memory,ax ;16K boundary
- jmp get_emb ;Loop back and try again
-
- init7: mov emb_handle,dx ;Save EMB handle
- mov ax,memory ;Calculate the number of
- mov cl,4 ;pages and save the result
- shr ax,cl ;for later
- mov pages,ax
- ;
- ; Alter the interrupt 67h vector, compute the break address, and return.
- ;
- mov ah,09h ;Display the size of the
- mov dx,offset msg1 ;EMS memory pool
- int 21h
- mov ax,memory
- call bin2asc
- mov ah,09h
- mov dx,offset msg2
- int 21h
-
- mov ax,pages ;Compute the address of
- shl ax,1 ;the handle table
- shl ax,1
- add ax,offset page_table
- mov hndl_table_addr,ax ;Save it
- add ax,handles ;Compute ending address
-
- add ax,15 ;Compute the segment address
- mov cl,4 ;of the next higher para-
- shr ax,cl ;graph in memory for the
- mov bx,cs ;page frame address
- add ax,bx
-
- mov page_frame,ax ;Save page frame address
- add ax,1000h ;Add 1000h for break address
- mov word ptr es:[di+14],0 ;Store the break address in
- mov word ptr es:[di+16],ax ;the request header
-
- xor ax,ax ;Grab the INT 67h vector
- mov es,ax
- cli
- mov word ptr es:[19Ch],offset int67h
- mov word ptr es:[19Eh],cs
- sti
- ret
- init endp
-
- ;****************************************************************************
- ; FINDCHAR advances SI to the next non-white-space character. On return,
- ; carry set indicates EOL was encountered.
- ;****************************************************************************
-
- findchar proc near
- lodsb ;Get the next character
- cmp al,09h ;Loop if tab
- je findchar
- cmp al,20h ;Loop if space
- je findchar
- cmp al,2Ch ;Loop if comma
- je findchar
- dec si ;Point SI to the character
- cmp al,0Dh ;Exit with carry set if end
- je eol ;of line is reached
- cmp al,0Ah
- je eol
-
- clc ;Clear carry and exit
- ret
-
- eol: stc ;Set carry and exit
- ret
- findchar endp
-
- ;****************************************************************************
- ; FINDDELIM advances SI to the next white-space character. On return,
- ; carry set indicates EOL was encountered.
- ;****************************************************************************
-
- finddelim proc near
- lodsb ;Get the next character
- cmp al,09h ;Exit if tab
- je findchar
- cmp al,20h ;Exit if space
- je fd_exit
- cmp al,2Ch ;Exit if comma
- je fd_exit
- cmp al,0Ah ;Exit if line feed
- je fd_eol
- cmp al,0Dh ;Loop back for more if end
- jne finddelim ;of line isn't reached
-
- fd_eol: dec si ;Set carry and exit
- stc
- ret
-
- fd_exit: dec si ;Clear carry and exit
- clc
- ret
- finddelim endp
-
- ;****************************************************************************
- ; ASC2BIN converts a decimal number entered in ASCII form into a binary
- ; value in AX. Carry set on return indicates that an error occurred in
- ; the conversion.
- ;****************************************************************************
-
- asc2bin proc near
- xor ax,ax ;Initialize registers
- xor bx,bx
- mov cx,10
-
- a2b_loop: mov bl,[si] ;Get a character
- inc si
- cmp bl,20h ;Exit if space
- je a2b_exit
- cmp bl,2Ch ;Exit if comma
- je a2b_exit
- cmp bl,0Dh ;Exit if carriage return
- je a2b_exit
- cmp bl,0Ah ;Exit if line feed
- je a2b_exit
-
- cmp bl,"0" ;Error if character is not
- jb a2b_error ;a number
- cmp bl,"9"
- ja a2b_error
-
- mul cx ;Multiply the value in AX by
- jc a2b_error ;10 and exit on overflow
- sub bl,30h ;Convert ASCII to binary
- add ax,bx ;Add latest value to AX
- jnc a2b_loop ;Loop back for more if sum
- ;is less than 65,535
-
- a2b_error: dec si ;Set carry and exit
- stc
- ret
-
- a2b_exit: dec si ;Clear carry and exit
- clc
- ret
- asc2bin endp
-
- ;****************************************************************************
- ; BIN2ASC converts a binary value in AX to ASCII form and displays it.
- ;****************************************************************************
-
- bin2asc proc near
- mov bx,10 ;Initialize divisor word and
- xor cx,cx ;digit counter
- b2a1: inc cx ;Increment digit count
- xor dx,dx ;Divide by 10
- div bx
- push dx ;Save remainder on stack
- or ax,ax ;Loop until quotient is zero
- jnz b2a1
- b2a2: pop dx ;Retrieve a digit from stack
- add dl,30h ;Convert it to ASCII
- mov ah,2 ;Display it
- int 21h
- loop b2a2 ;Loop until done
- ret
- bin2asc endp
-
- code ends
- end
-